using System;
using System.Collections.Generic;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.IO;
using System.Windows.Forms;
using ZedGraph;
using System.Linq;
using System.Drawing.Drawing2D;
using System.Data.OleDb;
using System.Data;

namespace Fit_Growth_Curves
{

    public partial class FitterForm : Form
    {
        //public string FileLocations = @"C:\Various_Dependencies\GrowthCurve\";
        public const double BAD_DATA_VALUE = -999;
        public bool Is_48WellDataLoaded = true;
        double ChartNLastFitXValue= BAD_DATA_VALUE;
        double ChartPickDataLastFitXValue = BAD_DATA_VALUE;
        private DateTime[] DateTimesinFile;//This will be the list of all of the Datetimes in the file,
        //individual growth curves might
        //not have data everywhere
        public FitterForm()
        {
            InitializeComponent();
            txtEnterDataInstructions.Rtf=@"{\rtf1\ansi\ansicpg1252\deff0\deflang1033{\fonttbl{\f0\fswiss\fcharset0 Arial;}}{\*\generator Msftedit 5.41.21.2508;}\viewkind4\uc1\pard\qc\b\f0\fs20 The Enter Data Tab\par\pard\par" 
            +@"\b0\tab There are three ways to enter data into this program.  The first involves making a file with the raw data (say in excel) and importing it directly.  Directions on how to make this file are on the website.  The second way is to import the data files that are generated by the Caliper robots, talk to Nigel about any questions you have in doing this.\par\par\tab Finally, you can also enter data by using this tab.  To do this, first name your data in the text box at left. Then for each time point in your dataset, type this time into the box in the upper left and hit the 'Create New Data Point at this Time' button.  Finally, go into the datasheet in the middle and add all of the OD values at these time points.  When all of your data is entered, hit the 'Add and Fit Data' button.  You can then go back to the 'View and Fit Data' tab to work with your data, or you can clear the table and add more data (be sure to give it a different name though).\b\par\b0\par";
            selectablePlateMap1.GroupsChanged += new SelectablePlateMap.ChangedEventHandler(selectablePlateMap1_GroupsChanged);
            TreatmentTextBoxes[1] = txtTreatment1;
            TreatmentTextBoxes[2] = txtTreatment2;
            TreatmentTextBoxes[3] = txtTreatment3;
            TreatmentTextBoxes[4] = txtTreatment4;
            TreatmentTextBoxes[5] = txtTreatment5;
            TreatmentTextBoxes[6] = txtTreatment6;
            ChartN.ZoomEvent += new ZedGraphControl.ZoomEventHandler(ChartN_ZoomEvent);
            ChartPickData.ZoomEvent+=new ZedGraphControl.ZoomEventHandler(ChartPickData_ZoomEvent);
            toDeletePlateMap.IndividualWellChanged += new SelectablePlateMap.ChangedEventHandler(toDeletePlateMap_IndividualWellChanged);
            toDeletePlateMap.SHOW_GROUP_NUMBER = false;
        }

   

        void  ChartPickData_ZoomEvent(ZedGraphControl sender, ZoomState oldState, ZoomState newState)
{
 	if (ChartPickDataLastFitXValue != BAD_DATA_VALUE)
            {
                RefitCurve(ChartPickDataLastFitXValue);
                ChartPickDataLastFitXValue = BAD_DATA_VALUE;
            }
}
        //really backwards way to undo a point fit change due to a zoom event
        void ChartN_ZoomEvent(ZedGraphControl sender, ZoomState oldState, ZoomState newState)
        {
            if (ChartNLastFitXValue != BAD_DATA_VALUE)
            {
                RefitCurve(ChartNLastFitXValue);
                ChartNLastFitXValue = BAD_DATA_VALUE;
            }
        }

        
        private void Form1_Load(object sender, EventArgs e)
        {
            
            ChartN.GraphPane.Title.Text = "";
            ChartN.GraphPane.XAxis.Title.Text = "";
            ChartN.GraphPane.YAxis.Title.Text = "";

            ChartSlopeN.GraphPane.YAxis.Title.Text = "";
            ChartSlopeN.GraphPane.XAxis.Title.Text = "";
            ChartSlopeN.GraphPane.Title.Text = "";
            
            MakeEnterDataTable();//makes the table for the enter data tab
            PickSampleTime.Text = System.DateTime.Now.ToString();       
        }
        private double[] ConvertDoubleArraytoOneDimension(int length, int column, double[,] ArrayToTrim)
        {
            //This method takes the oversized arrays initialized during data collection returns one column of it
            //trimed to the appropriate length
            //copy data into new smaller arrays, probably not efficent here
            double[] ODTemp = new double[length];
            for (int i = 0; i < length; i++)
            {
                ODTemp[i] = ArrayToTrim[i, column];
            }
            return ODTemp;
        }
        private DateTime[] ConvertDateTimeArray(int length, DateTime[] ArrayToTrim)
        {
            //This method takes the oversized arrays initialized during data collection and trims them down.
            DateTime[] acTimeTemp = new DateTime[length];
            for (int i = 0; i < length; i++)
            {
                acTimeTemp[i] = ArrayToTrim[i];
            }
            return acTimeTemp;
        }
        private void GetData(string FullFileName, bool CalculateLagTime)
        {
            //first to create an array of values, I know there will be 48 columns in the second one,
            //and for now I am going to assume we will have 200 datapoints, which we will not!
            StreamReader SR = new StreamReader(FullFileName);
            string line;
            int MaxDataPoints = 500;
            string[] titles;// = new string[1];//holds all the titles
            double[,] absDATA;// = new double[1, 1];
            DateTime[] acTimeValues;// = new DateTime[1];//time values as a datetime
            int currentrow = 0;

            //get titles
            line = SR.ReadLine();
            string[] splitit = line.Split(',');//title should be of the form #Time, Data1,Data2,Data3;
            titles = new string[splitit.Length - 1];
            for (int i = 1; i < splitit.Length; i++)
            { titles[i - 1] = splitit[i]; }//add title names

            //reset values for matrices
            acTimeValues = new DateTime[MaxDataPoints];
            absDATA = new double[MaxDataPoints, titles.Length];
            currentrow = 0;
            while ((line = SR.ReadLine()) != null && line.Length > 0 && !(line.StartsWith(",,")))
            {
                splitit = line.Split(',');
                acTimeValues[currentrow] = Convert.ToDateTime(splitit[0]);//add the time value
                for (int i = 1; i < splitit.Length; i++)//was -1
                { absDATA[currentrow, i - 1] = Convert.ToDouble(splitit[i]); }//add datetime
                currentrow++;
                if (currentrow >= 500)
                {
                    Exception ex = new Exception("Ooops, you have more then 500 data points, didn't expect that, talk to Nigel");
                    throw ex;
                }
            }
            SendDataToGrowthCurve(currentrow, absDATA, acTimeValues, titles,CalculateLagTime);
            SR.Close();
            lstGrowthCurves.SelectedIndex = 0;
        }
        private void UpdateDateTimesInFile(DateTime[] TimeValues)
        {
            //This is used to update the DateTimes when someone manually enters data
            //this will remake the array everytime it finds a new value (hopefully this will occur rarely)
            if(DateTimesinFile==null){DateTimesinFile=TimeValues;}
            else
            {
                DateTime[] OldValues = DateTimesinFile;
            foreach (DateTime InputtedDateTime in TimeValues)
            {
                bool inArray = false;
                foreach (DateTime dt in DateTimesinFile)
                {
                    if (dt.Equals(InputtedDateTime))
                    { inArray = true; break; }
                }
                if (!inArray)
                {
                    DateTimesinFile = new DateTime[DateTimesinFile.Length + 1];
                    for (int i = 0; i < DateTimesinFile.Length - 1;i++ )
                    {
                        //slow loop here, redoing it each time
                        DateTimesinFile[i] = OldValues[i];
                    }
                    DateTimesinFile[DateTimesinFile.Length - 1] = InputtedDateTime;
                    OldValues = DateTimesinFile;
                }
            }
            }
        }
        private void AddGrowthRateDataToBoxes(GrowthData GR)
        {
            lstGrowthCurves.Items.Add(GR);
            lstGrowthCurvesMirror.Items.Add(GR.ToString());
            lstMultiplePlots.Items.Add(GR.ToString());
        }
        private void SendDataToGrowthCurve(int currentrow, double[,] absDATA, DateTime[] acTimeValues, string[] titles, bool CalculateLagTime)
        {
            acTimeValues = ConvertDateTimeArray(currentrow, acTimeValues);
            UpdateDateTimesInFile(acTimeValues);
            for (int i = 0; i < titles.Length; i++)
            {
                // if (absDATA[0, 2] == 0) { throw new Exception(); }
                double[] ODDATA = ConvertDoubleArraytoOneDimension(currentrow, i, absDATA);
                GrowthData GR = new GrowthData(titles[i], acTimeValues, ODDATA,CalculateLagTime);
                AddGrowthRateDataToBoxes(GR);
            }
        }
        private void ResetChart()
        {
            ChartN.GraphPane.Title.Text = "Log[OD600]";
            //Chart.ChartArea.AxisY.Text = "Log[OD600]";
            ChartN.GraphPane.XAxis.Title.Text= "Hours";

            //ChartSlope.Header.Text = "Doubling Time Between Intervals";
            ChartStandard.GraphPane.Title.Text = "OD[600]";
            txtMaxRange.Text = "";
            txtMaxRange.Text = "";
            lstData.Items.Clear();
            ChartN.GraphPane.CurveList.Clear();
            ChartSlopeN.GraphPane.CurveList.Clear();
            ChartSlopeN.GraphPane.YAxis.Scale.MagAuto = true;
            ChartStandard.GraphPane.CurveList.Clear();
            ChartPickData.GraphPane.CurveList.Clear();
            tblRawData.Visible = false;
        }
        private void FillDataGrid(GrowthData GR)
        {
            tblRawData.Visible = true;
            DataTable DT = new DataTable();
            DataColumn col = new DataColumn("Time", System.Type.GetType("System.DateTime"));
            DT.Columns.Add(col);
            col = new DataColumn("OD Value", System.Type.GetType("System.Double"));
            DT.Columns.Add(col);
            col = new DataColumn("Fitted?", System.Type.GetType("System.Boolean"));
            DT.Columns.Add(col);

            for (int i = 0; i < GR.timeValues.Length; i++)
            {
                DataRow row = DT.NewRow();
                row[0] = GR.timeValues[i];
                row[1] = GR.ODValues[i];
                if (GR.ValidDataSet && SimpleFunctions.ValueInArray(GR.FittedXValues, GR.TimeValuesDecimal[i]))//now decide if it made it into the fit
                {
                    row[2] = true;
                }
                else { row[2] = false; }
                DT.Rows.Add(row);
            }
            tblRawData.DataSource = DT;

        }
        private void RefreshGraphs()
        {
            if (lstGrowthCurves.SelectedIndex != -1)
            {
                lstGrowthCurvesMirror.SelectedIndex = lstGrowthCurves.SelectedIndex;
                try
                {
                    ResetChart();
                    ChartNLastFitXValue = BAD_DATA_VALUE;
                    ChartNLastFitXValue=BAD_DATA_VALUE;
                    GrowthData toPlot = (GrowthData)lstGrowthCurves.SelectedItem;
                    plotGrowthData(toPlot, true);
                    lstallData(toPlot);
                    FillDataGrid(toPlot);
                }
                catch (Exception thrown)
                {
                    MessageBox.Show("Could not plot this data, check the input file\n Exact error: " + thrown.Message);
                }
            }
        }
        private void lstGrowthCurves_SelectedIndexChanged(object sender, EventArgs e)
        {
            RefreshGraphs();
        }
        private void lstallData(GrowthData toList)
        {
            lstData.Items.Clear();
            lstDataMirror.Items.Clear();

            lstData.Items.Add("Maximum Doubling Time: " + toList.MaxGrowthRate.MaxGrowthRate.ToString("n3"));
            //lstDataMirror.Items.Add("Maximum Doubling Time: " + toList.MaxGrowthRate.MaxGrowthRate.ToString("n3"));
            if (toList.ValidDataSet)
            {
                double Rate = Math.Log(2)/toList.GrowthRate.GrowthRate;
                lstData.Items.Add("Growth Rate: " + toList.GrowthRate.GrowthRate.ToString("n3"));
                lstData.Items.Add("Fitted Method: " + toList.GrowthRate.FittingUsed);
                lstData.Items.Add("R2= " + toList.GrowthRate.R2.ToString("n4"));
                lstData.Items.Add("RMSE = " + toList.GrowthRate.RMSE.ToString("e3"));
                lstData.Items.Add("Num Points = " + toList.GrowthRate.NumPoints.ToString());
                lstData.Items.Add("Fitted Doubling Time: " + Rate.ToString("n4"));
                
                //lstDataMirror.Items.Add("Fitted Doubling Time: " + toList.GrowthRate.GrowthRate.ToString("n3"));
                //lstDataMirror.Items.Add("Fitted Method: " + toList.GrowthRate.FittingUsed);
                //lstDataMirror.Items.Add("R2= " + toList.GrowthRate.R2.ToString("n4"));
                //lstDataMirror.Items.Add("RMSE = " + toList.GrowthRate.RMSE.ToString("e3"));
                //lstDataMirror.Items.Add("Num Points = " + toList.GrowthRate.NumPoints.ToString());
                //lstDataMirror.Items.Add("Growth Rate = " +Rate.ToString("n4"));

                if (toList.FirstReadingisODAtTimeZero)
                {
                    lstData.Items.Add("Lag Time = " + toList.LagTime.ToString("n3"));
                    //lstDataMirror.Items.Add("Lag Time = " + toList.LagTime.ToString("n3"));
                }
                if (toList.DataFromDatabase)
                {
                    lstData.Items.Add("Max OD FLAG = " +toList.db_MaxOD_Flag.ToString());
                    lstData.Items.Add("Growth Rate Flag = " + toList.db_GrowthRateFLAG.ToString());
                }
          
            }
            foreach(object o in lstData.Items)
            {
                lstDataMirror.Items.Add(o);
            }
        }
        private void SetLineValues(LineItem ToChange, Color ColorToUse)
        {
            ToChange.Symbol.Fill.IsVisible = true;
            ToChange.Symbol.Fill.Color = ColorToUse;
            ToChange.Symbol.Size = 10;
            ToChange.Line.Width = 3;
            
        }
        private void plotGrowthData(GrowthData toPlot, bool ShowPredicted)
        {
            
            //Manual override here, these never plot well
            if (ShowPredicted && toPlot.MaxGrowthRate.MaxGrowthRate == GrowthData.DEFAULT_MAX_GROWTH_RATE)
            { ShowPredicted = false; }
            GraphPane ChartNGraph = ChartN.GraphPane;
            ChartNGraph.Title.IsVisible = false;
            ChartNGraph.XAxis.Title.Text = "Hours";
            ChartNGraph.YAxis.Title.Text = "Log OD[600]";
            ChartNGraph.Legend.IsVisible = true;
            SetLineValues(ChartN.GraphPane.AddCurve("Values", toPlot.TimeValuesDecimal, toPlot.LogODValues, Color.CadetBlue, SymbolType.Square),Color.DarkBlue);
            bool ShouldPlot;
            if (GrowthData.USE_EXPONENTIAL_FITTING) ShouldPlot = toPlot.ExpModelFitted;
            else ShouldPlot = (toPlot.LinearModelFitted && toPlot.MaxGrowthRate.MaxGrowthRate!=GrowthData.DEFAULT_MAX_GROWTH_RATE);
            if (toPlot.FirstReadingisODAtTimeZero && ShouldPlot)
            {
                double[] xlagval= new double[1];
                double[] ylagval=new double[1];
                xlagval[0]=toPlot.LagTime;
                ylagval[0]=toPlot.LogODValues[0];
                SetLineValues(ChartN.GraphPane.AddCurve("Lag Time Ends", xlagval, ylagval, Color.Red, SymbolType.Square), Color.Red);
            }
            //Now The Data THAT WAS USED TO MAKE THE FIT
            if (toPlot.ValidDataSet && toPlot.FittedXValues.Length > 1)
            {
                PointPairList PL = new PointPairList(toPlot.FittedXValues, toPlot.FittedLogYValues);
                SetLineValues(ChartN.GraphPane.AddCurve("Fitted Values", PL, Color.BlueViolet, SymbolType.Square), Color.Violet);
            }
            //NOW THE FIT ITSELF
            if (toPlot.ExpModelFitted && GrowthData.USE_EXPONENTIAL_FITTING && ShowPredicted)
            {
                //IF THE DATA HAS BEEN FIT, THIS FIRST ROUTINE WILL PLOT THE FITTED line on the top log graph
                //not this fit is from the exponential
                double[] x, y;
                toPlot.ExpFit.GenerateFitLine(0, .1, SimpleFunctions.Max(toPlot.FittedXValues), out x, out y);
                for (int i = 0; i < y.Length; i++)
                {
                    if (y[i] == 0) { continue; }
                    y[i] = Math.Log(y[i]);
                }
                PointPairList ExpFitted = new PointPairList(x, y);
                LineItem ExpFitLineNormal= ChartN.GraphPane.AddCurve("Exp Fit", ExpFitted, Color.Plum, SymbolType.Plus);
                ExpFitLineNormal.Symbol.IsVisible = false;
                ExpFitLineNormal.Line.Width = 3;   
                
            }
            else if (toPlot.LinearModelFitted && !GrowthData.USE_EXPONENTIAL_FITTING && ShowPredicted)
            {
                //IF THE DATA HAS BEEN FIT, THIS FIRST ROUTINE WILL PLOT THE FITTED line on the top log graph
                //not this fit is from the exponential
                double[] x, y;
                toPlot.LinFit.GenerateFitLine(0, .1, SimpleFunctions.Max(toPlot.FittedXValues), out x, out y);
                PointPairList LinFitted = new PointPairList(x, y);
                LineItem LinFitLineNormal = ChartN.GraphPane.AddCurve("Lin Fit", LinFitted, Color.Plum, SymbolType.Plus);
                LinFitLineNormal.Symbol.IsVisible = false;
                LinFitLineNormal.Line.Width = 3;

            }
            if ((chkShowLin.Checked && toPlot.LinearModelFitted) || (!GrowthData.USE_EXPONENTIAL_FITTING && toPlot.LinearModelFitted))
            {
                double[] x, y;
                
                //Now the predicted line from the linear fit plotted NORMALLY
                toPlot.LinFit.GenerateFitLine(SimpleFunctions.Min(toPlot.FittedXValues), .1, SimpleFunctions.Max(toPlot.FittedXValues), out x, out y);
                //C1.Win.C1Chart.ChartDataSeries srs2 = new C1.Win.C1Chart.ChartDataSeries();
                double[] y3 = new double[y.Length];
                //srs = new C1.Win.C1Chart.ChartDataSeries();
                for (int i = 0; i < y.Length; i++)
                {
                    y3[i] = Math.Exp(y[i]);
                }
                SimpleFunctions.CleanNonRealNumbersFromYvaluesInXYPair(ref x, ref y);
                SetLineValues(ChartStandard.GraphPane.AddCurve("Lin Fit",x,y3,Color.Green,SymbolType.None),Color.Green);
                ChartStandard.GraphPane.Legend.IsVisible=true;
            }

            //NOW FOR THE NORMAL SCALE
            if (toPlot.MaxGrowthRate.MaxGrowthRate != GrowthData.DEFAULT_MAX_GROWTH_RATE)
            {
                //NormalScal-inuse
                if (toPlot.LinearModelFitted && ShowPredicted)
                {
                    double[] toPlotX = toPlot.FittedXValues;
                    double[] toPlotY = toPlot.FittedYValues;
                    SimpleFunctions.CleanNonRealNumbersFromYvaluesInXYPair(ref toPlotX, ref toPlotY);
                    ChartStandard.GraphPane.AddCurve("Fitted Data", toPlotX, toPlotY, Color.BlueViolet, SymbolType.Square);
                }
                //Now the predictedLine
                ChartStandard.GraphPane.AddCurve("Data",toPlot.TimeValuesDecimal,toPlot.ODValues,Color.Blue,SymbolType.Square);
                //Now to add the lag time
                if (toPlot.FirstReadingisODAtTimeZero && ShouldPlot)
                {
                    double[] lagx = new double[1];
                    double[] lagy = new double[1];
                    lagx[0] = toPlot.LagTime;
                    lagy[0] = toPlot.ODValues[0];
                    ChartStandard.GraphPane.AddCurve("Lag Time Ends", lagx, lagy, Color.Red, SymbolType.Triangle);
                }

               
                if (toPlot.ExpModelFitted)
                {
                    //First the actual exponential fit
                    double[] x1, y1;
                    toPlot.ExpFit.GenerateFitLine(0, .1, SimpleFunctions.Max(toPlot.FittedXValues), out x1, out y1);
                    SimpleFunctions.CleanNonRealNumbersFromYvaluesInXYPair(ref x1, ref y1);
                    if (x1.Length > 0)
                    {
                        ChartStandard.GraphPane.AddCurve("Exp Fit", x1, y1, Color.Plum, SymbolType.None);
                   }
                }
                CreatePickDataPlot(toPlot);
            }
            else
            {
                ChartPickData.GraphPane.Title.Text = "This was too weird to plot";
                ChartPickData.GraphPane.CurveList.Clear();

                ChartStandard.GraphPane.Title.Text = "This was too weird to plot";
                ChartStandard.GraphPane.CurveList.Clear();
            }
            //NOW THE SLOPE GRAPH
            //FIRST FOR AN INFINITY CHECK
            ChartSlopeN.GraphPane.AddCurve("DoublingTime", toPlot.XvaluesForSlope, toPlot.SlopeChange, Color.Black, SymbolType.Square);
            ChartSlopeN.GraphPane.Legend.IsVisible = false;
            ChartSlopeN.GraphPane.YAxis.Title.Text = "Hours";
            ChartSlopeN.GraphPane.XAxis.Title.Text = "Right Side Time Value";
            ChartSlopeN.GraphPane.Title.Text = "Doubling Time Between Reads";
            txtMaxRange.Text = ChartSlopeN.GraphPane.YAxis.Scale.Max.ToString();
            txtMinRange.Text = ChartSlopeN.GraphPane.YAxis.Scale.Min.ToString();

            //Now to make sure the order is right, reverse everything
           ChartN.GraphPane.CurveList.Reverse();
           ChartSlopeN.GraphPane.CurveList.Reverse();
           ChartPickData.GraphPane.CurveList.Reverse();

            ChartN.GraphPane.AxisChange();
            ChartSlopeN.GraphPane.AxisChange();
            ChartStandard.GraphPane.AxisChange();
            ChartPickData.GraphPane.AxisChange();
            
            ChartN.Refresh();
            ChartSlopeN.Refresh();
            ChartPickData.Refresh();
            ChartStandard.Refresh();
        }
        private void CreatePickDataPlot(GrowthData toPlot)
        {

            ChartPickData.GraphPane.Title.Text = "Pick a Value to Change it";
            ChartPickData.GraphPane.XAxis.Title.Text = "Time";
            ChartPickData.GraphPane.YAxis.Title.Text = "Log[OD600]";
            SetLineValues(ChartPickData.GraphPane.AddCurve("", toPlot.TimeValuesDecimal, toPlot.LogODValues, Color.Blue, SymbolType.Square), Color.Blue);
            //Now The Data in the fit
            if (toPlot.ValidDataSet && toPlot.GrowthRate.FitterUsed!=null  && chkShowFittedPick.Checked)
            {
                SetLineValues(ChartPickData.GraphPane.AddCurve("Fitted", toPlot.FittedXValues, toPlot.FittedLogYValues, Color.BlueViolet, SymbolType.Square), Color.BlueViolet);
                double[] x, y;
                
                toPlot.GrowthRate.FitterUsed.GenerateFitLine(0, .1, SimpleFunctions.Max(toPlot.FittedXValues), out x, out y);
                if (toPlot.GrowthRate.FitterUsed is ExponentialFit)
                {
                    y = y.Select((q) => Math.Log(q)).ToArray();
                }
                PointPairList Fitted = new PointPairList(x, y);
                LineItem FitLineNormal = ChartPickData.GraphPane.AddCurve(toPlot.GrowthRate.FittingUsed, Fitted, Color.Plum, SymbolType.Plus);
                FitLineNormal.Symbol.IsVisible = false;
                FitLineNormal.Line.Width = 2;
                
            }
        }
        public void LoadFile(string FileName)
        {
            ClearLists();
            
                this.Text = "Fit Growth Curves - " + FileName;
                try { GetData(openFileDialog1.FileName, false); }
                catch (Exception thrown) { MessageBox.Show("Could not open the file, please check the format \n Also, make sure it is not open by another program\n\n  Error: " + thrown.Message); }
            

        }
        private void SelectFileToOpen(bool CalculateLagTime)
        {
            ClearLists();
            openFileDialog1.Title = "Select the file with Growth Curve Data";
            openFileDialog1.Filter = "CSV Files | *.csv|All Files | *.csv";
            openFileDialog1.ShowDialog();
            if (openFileDialog1.FileName.Length > 0)
            {
                this.Text = "Fit Growth Curves - " + openFileDialog1.FileName;
                try { GetData(openFileDialog1.FileName,CalculateLagTime); }
                catch (Exception thrown) { MessageBox.Show("Could not open the file, please check the format \n Also, make sure it is not open by another program\n\n  Error: " + thrown.Message); }
            }
            else { MessageBox.Show("You must pick a file"); }//this.Close(); }

        }
        private void MenuOpenFile_Click(object sender, EventArgs e)
        {
            SelectFileToOpen(false);
        }
        private void btnChangeAxis_Click(object sender, EventArgs e)
        {
            try
            {
                ChartSlopeN.GraphPane.YAxis.Scale.Min=Convert.ToDouble(txtMinRange.Text);
                ChartSlopeN.GraphPane.YAxis.Scale.Max = Convert.ToDouble(txtMaxRange.Text);
                ChartSlopeN.Refresh();
            }
            catch
            {
                MessageBox.Show("Could not change Y axis, please check your inputs");
            }
        }
        private void exportDataToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            saveFileDialog1.AddExtension = true;
            saveFileDialog1.DefaultExt = ".csv";
            saveFileDialog1.Filter = "CSV FILE(*.csv) | *.csv";
            saveFileDialog1.ShowDialog();
            if (saveFileDialog1.FileName.Length > 0)
            {
                try { ExportData(saveFileDialog1.FileName); }
                catch(Exception thrown)
                { MessageBox.Show("Could not save the file, please check the format\nActual Error is:  "+thrown.Message); }
            }
            else { MessageBox.Show("You must pick a file"); }
        }
        private void lstGrowthCurvesMirror_SelectedIndexChanged(object sender, EventArgs e)
        {
            lstGrowthCurves.SelectedIndex = lstGrowthCurvesMirror.SelectedIndex;
        }
        private void importPreviousToolStripMenuItem_Click(object sender, EventArgs e)
        {
            string Filename = "";
            try
            {
                DialogResult DR = openFileDialog1.ShowDialog();
                openFileDialog1.Filter = "CSV FILE(*.csv) | *.csv"; 
                if (DR == DialogResult.OK)
                {
                    Filename = openFileDialog1.FileName;
                    importPreviousDataFile(Filename);
                    this.Text = "Growth Curve " + openFileDialog1.FileName;
                }
            }
            catch (Exception thrown)
            {
                MessageBox.Show("Unable to import this file, this could have corrupted the program and it is recommended that you save "
                + "and restart.  Check your file to insure that you did not alter the formatting after it was exported from the curve fitter, excel will do "
                + "this without telling you.  Talk to Nigel to correct these issues\n\n\n" + thrown.Message + "\n\n\n" + Filename, "File Import Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            

        }
        private void importPreviousDataFile(string file)
        {
            lstGrowthCurves.Items.Clear();
            lstGrowthCurvesMirror.Items.Clear();
            lstMultiplePlots.Items.Clear();

            //string file = @"C:\Users\Nigel Delaney\Desktop\Temp_Rep\Td_PopA-rep3.csv";
            StreamReader SR = new StreamReader(file);
            {
                bool LagShouldBeCalculated = false;
                //drop two header lines
                SR.ReadLine();
                SR.ReadLine();
                string line="";
                ArrayList FitSummaryLines = new ArrayList();
                while ((line = SR.ReadLine()) != null)
                {
                    if (!line.StartsWith("Complete Data Listing Below"))
                    {FitSummaryLines.Add(line);}
                    else { break; } 
                }
                //Now to see if there is lag time
                if (line.Contains("-Initial OD Present"))//I add this to the end of the complete data listing if need be
                {
                    LagShouldBeCalculated = true;
                }

                //now to grab the more important data
                ArrayList CompleteDataListing = new ArrayList();
                SR.ReadLine();//blow through headerline
                while ((line = SR.ReadLine()) != null)
                {
                    if (line.Length > 3)
                    {
                        CompleteDataListing.Add(line.Split(','));
                    }
                }
                //now to add the datetimes to the file
                DateTime[] AllDateTimes = new DateTime[CompleteDataListing.Count];
                for (int i = 0; i < CompleteDataListing.Count; i++)
                {
                    AllDateTimes[i]=(Convert.ToDateTime((CompleteDataListing[i] as string[])[0]));
                }
                UpdateDateTimesInFile(AllDateTimes);
                //now to convert this into something useful 
                for (int i = 0; i < FitSummaryLines.Count; i++)
                {
                    ArrayList DateTimeArray = new ArrayList();
                    ArrayList ODValuesArray = new ArrayList();
                    ArrayList FlagsArray = new ArrayList();

                    string name = (string)FitSummaryLines[i];
                    name = name.Split(',')[0];
                    string notes = (string)FitSummaryLines[i];
                    notes = notes.Split(',')[9];
                    int dataposition = 1+i * 2;
                    for (int j = 0; j < CompleteDataListing.Count; j++)
                    {
                        if ((CompleteDataListing[j] as string[])[dataposition] != "-999")
                        {
                            DateTimeArray.Add(Convert.ToDateTime((CompleteDataListing[j] as string[])[0]));
                            ODValuesArray.Add(Convert.ToDouble((CompleteDataListing[j] as string[])[dataposition]));
                            FlagsArray.Add(Convert.ToInt32((CompleteDataListing[j] as string[])[dataposition + 1]));
                        }
                    }
                    DateTime[] Times = new DateTime[DateTimeArray.Count];
                    DateTimeArray.CopyTo(Times);
                    double[] ODvalues = new double[ODValuesArray.Count];
                    ODValuesArray.CopyTo(ODvalues);
                    int[] Flags = new int[FlagsArray.Count];
                    FlagsArray.CopyTo(Flags);
                    GrowthData GD = new GrowthData(name, Times, ODvalues, notes, Flags,LagShouldBeCalculated);
                    AddGrowthRateDataToBoxes(GD);
                }
                               
            }
        }
        private string runSaveFileDialog(string filtername, string ext)
        {
            saveFileDialog1.AddExtension = true;
            saveFileDialog1.DefaultExt = ext;
            saveFileDialog1.Filter = filtername;
            saveFileDialog1.ShowDialog();

            if (saveFileDialog1.FileName.Length > 0)
            {
                return saveFileDialog1.FileName;
            }
            else
            {
                MessageBox.Show("You must pick a file");
                return "Failed";
            }
        }
       
        private void btnDeleteCurve_Click(object sender, EventArgs e)
        {
            if (lstGrowthCurves.SelectedIndex != -1)
            {
                
                int toRemove=lstGrowthCurves.SelectedIndex;
                DeleteCurve(toRemove);
            }
        }
        private void DeleteCurve(int IndexToDelete)
        {
            ResetChart();
            lstGrowthCurves.Items.RemoveAt(IndexToDelete);
            lstGrowthCurvesMirror.Items.RemoveAt(IndexToDelete);
            lstMultiplePlots.Items.RemoveAt(IndexToDelete);
        }
        private void chkShowLin_CheckedChanged(object sender, EventArgs e)
        {
            lstGrowthCurves.SelectedIndex = lstGrowthCurves.SelectedIndex;
        }
        private void readThemHereToolStripMenuItem_Click(object sender, EventArgs e)
        {
            MessageBox.Show("If you enter data within the program, right now it will not report them in the outputed file, however it will give the fitted values");
        }
        private void RefreshMultiplePlots()
        {
            try
            {
                this.Cursor = Cursors.WaitCursor;
                ColorSymbolRotator CSR = new ColorSymbolRotator();
                GraphPane Graph = MultiplePlots.GraphPane;
                Graph.CurveList.Clear();
                Graph.Title.Text = "Growth Plots";
                Graph.XAxis.Title.Text = "Hours";
                if (chkMuliLog.Checked) { Graph.YAxis.Title.Text = "Log [OD600]"; }
                else { Graph.YAxis.Title.Text = "OD600"; }
                Graph.Legend.Position = LegendPos.InsideBotRight;
                Graph.Legend.FontSpec.Size = 8f;
                Graph.Legend.IsHStack = true;
                SymbolType SymboltoUse = SymbolType.Circle;
                foreach (int i in lstMultiplePlots.SelectedIndices)
                {
                    GrowthData GD = (GrowthData)lstGrowthCurves.Items[i];
                    PointPairList XY;
                    if (chkMuliLog.Checked)
                    { XY = new PointPairList(GD.TimeValuesDecimal, GD.LogODValues); }
                    else
                    { XY = new PointPairList(GD.TimeValuesDecimal, GD.ODValues); }
                    
                    if((i%10)==0){SymboltoUse=CSR.NextSymbol;}
                    MultiplePlots.GraphPane.AddCurve(GD.ToString(), XY, CSR.NextColor, SymboltoUse);
                }
                if (chkLegend.Checked)
                { MultiplePlots.GraphPane.Legend.IsVisible = true; }
                else { MultiplePlots.GraphPane.Legend.IsVisible = false; }

                Graph.XAxis.Scale.MaxGrace = .05;
                MultiplePlots.AxisChange();
                MultiplePlots.Invalidate();

                if (chkFillColors.Checked)
                {
                    Graph.Fill = new Fill(Color.PowderBlue, Color.White, 45.0f);
                    Graph.Chart.Fill = new Fill(Color.White, Color.Pink, 45.0f);
                }
                else
                {
                    Graph.Fill = new Fill(Color.White);
                    Graph.Chart.Fill = new Fill(Color.White);
                }
                    this.Cursor = Cursors.Default;
            }
            catch (Exception thrown)
            { MessageBox.Show("Could not make graph, talk to nigel.\n\nError is:\n" + thrown.Message,"Graph Error",MessageBoxButtons.OK,MessageBoxIcon.Error); }
            finally { this.Cursor = Cursors.Default; }
        }
        private void lstMultiplePlots_SelectedIndexChanged(object sender, EventArgs e)
        {
            RefreshMultiplePlots();
        }
        private void chkMuliLog_CheckedChanged(object sender, EventArgs e)
        {
            RefreshMultiplePlots();
        }
        private void saveMultipleChartToolStripMenuItem_Click(object sender, EventArgs e)
        {
            MessageBox.Show("Right Click On The Graph To Do This","Wrong Spot",MessageBoxButtons.OK,MessageBoxIcon.Information);
            //try
            //{
            //    saveFileDialog1.AddExtension = true;
            //    saveFileDialog1.Title="Save Multiple Plot Chart";
            //    saveFileDialog1.Filter = "JPG File (*.jpg)|*.jpg|PNG files (*.png)|*.png|GIF Files|*.gif|BMP |*.bmp";
            //    if (saveFileDialog1.ShowDialog() == DialogResult.OK)
            //    {
            //        string filename=saveFileDialog1.FileName;
            //        string ext = filename.Substring(filename.LastIndexOf('.'),4);
            //        System.Drawing.Imaging.ImageFormat SaveFormat = System.Drawing.Imaging.ImageFormat.Png;
            //        switch (ext)
            //        {
            //            case(".jpg"):
            //                SaveFormat=System.Drawing.Imaging.ImageFormat.Jpeg;
            //                break;
            //            case(".png"):
            //                SaveFormat = System.Drawing.Imaging.ImageFormat.Png;
            //                break;
            //            case(".gif"):
            //                SaveFormat = System.Drawing.Imaging.ImageFormat.Gif;            //                break;
            //            default:
            //                SaveFormat = System.Drawing.Imaging.ImageFormat.Bmp;
            //                break;
            //        }
            //        MultiplePlots.GraphPane.GetImage().Save(saveFileDialog1.FileName, SaveFormat);
            //    }
           // }
            //catch
            //{
             //   MessageBox.Show("Couldn't Save, talk to Nigel");
            //}                
        }
        private void chkFillColors_CheckedChanged(object sender, EventArgs e)
        {
            RefreshMultiplePlots();
        }
        private void chkLegend_CheckedChanged(object sender, EventArgs e)
        {
            if (chkLegend.Checked)
            {
                MultiplePlots.GraphPane.Legend.IsVisible = true;
            }
            else
            {
                MultiplePlots.GraphPane.Legend.IsVisible = false;
            }
            MultiplePlots.Invalidate();
        }
        private void btnTemp_Click(object sender, EventArgs e)
        {
            try
            {

                int startindex = Convert.ToInt32(txtStartPoint.Text)-1;
                int endindex = Convert.ToInt32(txtEndPoint.Text)-1;
                foreach (object GRs in lstGrowthCurves.Items)
                {
                    try
                    {
                        GrowthData GR = (GrowthData)GRs;
                        GR.SetFittedRange(startindex, endindex);
                    }
                    catch (Exception thrown)
                    {
                        MessageBox.Show("Failed to change range for : " + GRs.ToString() + "\nRecommend you shut down\n\n" + thrown.Message);
                    }
                }

                RefreshGraphs();
            }
            catch(Exception thrown) {MessageBox.Show("Error setting points\n\n"+thrown.Message); }
        }
        private void openFileWithInitialToolStripMenuItem_Click(object sender, EventArgs e)
        {
  
            SelectFileToOpen(true);
        }
        private void ClearLists()
        {
            lstGrowthCurves.Items.Clear();
            lstGrowthCurvesMirror.Items.Clear();
            lstMultiplePlots.Items.Clear();
            lstTimePoints.Items.Clear();
        }
        private void openDirectoryWithRobotDataToolStripMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                ClearLists();
                folderBrowserDialog1.Description = "Select the directory that contains ONLY the data files";
                DialogResult DR = folderBrowserDialog1.ShowDialog();
                if (DR == DialogResult.OK)
                {
                    ImportRobotData.GetData(folderBrowserDialog1.SelectedPath);
                    GetData(folderBrowserDialog1.SelectedPath +"\\"+ ImportRobotData.NameofTempFile,false);
                    if (lstGrowthCurves.Items.Count == 48)
                    {
                        Is_48WellDataLoaded = true;
                        GrowthData GR = lstGrowthCurves.SelectedItem as GrowthData;
                        foreach (double value in GR.TimeValuesDecimal)
                        {
                            lstTimePoints.Items.Add(value.ToString("n3"));
                        }
                    }
                    else { Is_48WellDataLoaded = false; }
                    this.Text = "Growth Curve " + folderBrowserDialog1.SelectedPath;
                }
               
            }
            catch(Exception thrown)
            {
                MessageBox.Show("Could not load the data, the error was:\n\n" + thrown.Message);
            }
        }
        private void SubtractBlankFromAll(double Blank)
        {
            txtBlankValue.Text = Blank.ToString();
            for (int z = 0; z < lstGrowthCurves.Items.Count; z++)
            {
                GrowthData GR = (GrowthData)lstGrowthCurves.Items[z];
                double[] ODvalues = GR.ODValues;
                for (int i = 0; i < ODvalues.Length; i++)
                {
                    ODvalues[i] = ODvalues[i] - Blank;
                    if (!SimpleFunctions.IsARealNumber(ODvalues[i]))
                    {
                        ODvalues[i] = BAD_DATA_VALUE;
                    }

                }
                string Name =GR.ToString();
                DateTime[] DT = GR.timeValues;
                lstGrowthCurves.Items[z] = new GrowthData(Name, DT, ODvalues, false,GR.data_DatabaseIDs,GR.db_ExperimentID,GR.IsIsolateData);
            }
        }
        /// <summary>
        /// Subtracts the first reading from each position as the blank
        /// </summary>
        private void SubtractFirstReadingFromAll()
        {
            for (int z = 0; z < lstGrowthCurves.Items.Count; z++)
            {
                GrowthData GR = (GrowthData)lstGrowthCurves.Items[z];
                double[] ODvalues = GR.ODValues;
                double toSubtract = ODvalues[0];
                for (int i = 0; i < ODvalues.Length; i++)
                {
                    ODvalues[i] = ODvalues[i] - toSubtract;
                    if (!SimpleFunctions.IsARealNumber(ODvalues[i]))
                    {
                        ODvalues[i] = BAD_DATA_VALUE;
                    }

                }
                string Name = GR.ToString();
                DateTime[] DT = GR.timeValues;
                lstGrowthCurves.Items[z] = new GrowthData(Name, DT, ODvalues, false, GR.data_DatabaseIDs, GR.db_ExperimentID,GR.IsIsolateData);
            }
        }
        private void SubtractSecondReadingFromAll()
        {
            for (int z = 0; z < lstGrowthCurves.Items.Count; z++)
            {
                GrowthData GR = (GrowthData)lstGrowthCurves.Items[z];
                double[] ODvalues = GR.ODValues;
                double toSubtract = ODvalues[1];
                for (int i = 0; i < ODvalues.Length; i++)
                {
                    ODvalues[i] = ODvalues[i] - toSubtract;
                    if (!SimpleFunctions.IsARealNumber(ODvalues[i]))
                    {
                        ODvalues[i] = BAD_DATA_VALUE;
                    }

                }
                string Name = GR.ToString();
                DateTime[] DT = GR.timeValues;
                lstGrowthCurves.Items[z] = new GrowthData(Name, DT, ODvalues, false,GR.data_DatabaseIDs,GR.db_ExperimentID,GR.IsIsolateData);
            }
        }
        private void SubtractAverageOfFirstThreeReadingsFromAll()
        {
            for (int z = 0; z < lstGrowthCurves.Items.Count; z++)
            {
                GrowthData GR = (GrowthData)lstGrowthCurves.Items[z];
                double[] ODvalues = GR.ODValues;
                double toSubtract = (ODvalues[0]+ODvalues[1]+ODvalues[2])/3.0;
                for (int i = 0; i < ODvalues.Length; i++)
                {
                    ODvalues[i] = ODvalues[i] - toSubtract;
                    if (!SimpleFunctions.IsARealNumber(ODvalues[i]))
                    {
                        ODvalues[i] = BAD_DATA_VALUE;
                    }

                }
                string Name = GR.ToString();
                DateTime[] DT = GR.timeValues;
                lstGrowthCurves.Items[z] = new GrowthData(Name, DT, ODvalues, false, GR.data_DatabaseIDs, GR.db_ExperimentID, GR.IsIsolateData);
            }
        }
        private void SubtractTimeSeriesBlankFromAll(double[] Blanks)
        {
            //This method is used to subtract a time series of blanks, so that each well is blanked by
            //all the other reads AT THAT TIME, so with 12 readings, there are effectively 12 blanks
            txtBlankValue.Text = "Time Variable Blank Used";
            for (int z = 0; z < lstGrowthCurves.Items.Count; z++)
            {
                GrowthData GR = (GrowthData)lstGrowthCurves.Items[z];
                double[] ODvalues = GR.ODValues;
                if(ODvalues.Length!=Blanks.Length)
                {MessageBox.Show("The blanks did not match all of the OD readings, it is likely that you do not have samples at each time point");}
                for (int i = 0; i < ODvalues.Length; i++)
                {
                    ODvalues[i] = ODvalues[i] - Blanks[i];
                }
                string Name = GR.ToString();
                DateTime[] DT = GR.timeValues;
                lstGrowthCurves.Items[z] = new GrowthData(Name, DT, ODvalues, false);
            }
        }
        private void button1_Click(object sender, EventArgs e)
        {
            int[] rows ={0, 1, 7, 8};
            int[] BlankIndexes=new int[(rows.Length*12)];//this is the index of the blank values in the listbox
            int indexer=0;
            for (int i = 0; i < rows.Length; i++)
            {
                for (int j = 0; j < 12; j++)
                {
                    BlankIndexes[indexer] = 12 * rows[i] + j;
                    indexer++;
                }                
            }
            //now to grab these blank values
            double BlankSum=0;
            double BlankCount=0;
            for (int i = 0; i < BlankIndexes.Length; i++)
            {
                GrowthData GD = (GrowthData)lstGrowthCurves.Items[i];
                foreach (double dbl in GD.ODValues)
                {
                    BlankSum += dbl;
                    BlankCount++;
                }
            }
            double Blank = BlankSum / BlankCount;
            SubtractBlankFromAll(Blank);   
        }
        private void btnSubtractWrittenBlank_Click(object sender, EventArgs e)
        {
            try
            {
                SubtractBlankFromAll(Convert.ToDouble(txtBlankValue.Text));
            }
            catch { MessageBox.Show("Error, could not subtract a blank, did you write a number in the box?"); }
        }
        private void btnDeleteBlanks_Click(object sender, EventArgs e)
        {
            this.Cursor = Cursors.WaitCursor;
            int[] rows ={ 0, 1, 6, 7 };
            int[] BlankIndexes = new int[(rows.Length * 12)];//this is the index of the blank values in the listbox
            int indexer = 0;
            for (int i = 0; i < rows.Length; i++)
            {
                for (int j = 0; j < 12; j++)
                {
                    BlankIndexes[indexer] = 12 * rows[i] + j;
                    indexer++;
                }
            }
            for (int i = BlankIndexes.Length - 1; i > -1; i--)
            {
                //MessageBox.Show(lstGrowthCurves.Items.Count.ToString()+" "+BlankIndexes[i].ToString());
                lstGrowthCurves.Items.RemoveAt(BlankIndexes[i]);
                lstGrowthCurvesMirror.Items.RemoveAt(BlankIndexes[i]);
                lstMultiplePlots.Items.RemoveAt(BlankIndexes[i]);
            }
            this.Cursor = Cursors.Default;            
        }
        private void tabRobo_Paint(object sender, PaintEventArgs e)
        {
            this.SuspendLayout();
            try
            {   
                double[] Data;
                if(Is_48WellDataLoaded){Data= new double[48];}
                else{Data=new double[96];}

                //Initialize the plate tools class to make the color map
                Plate_Tools PT = new Plate_Tools(this,Is_48WellDataLoaded);
                for (int z = 0; z < lstGrowthCurves.Items.Count; z++)
                {
                    GrowthData GR = (GrowthData)lstGrowthCurves.Items[z];
                    int IndexOfCell = PT.CellNameToInts[GR.ToString()];//Get the index of the cell position from its name
                    if (rbtnGrowthRate.Checked)
                    {
                        Data[IndexOfCell] = GR.GrowthRate.GrowthRate;
                    }
                    else if (rbtnMaxOD.Checked)
                    {
                        Data[IndexOfCell] = GR.HighestRealODValue;
                        
                    }
                    else if (rbtnRS.Checked)
                    {
                        Data[IndexOfCell] = GR.GrowthRate.R2;
                    }
                    else if (rbtnIOD.Checked)
                    {
                        Data[IndexOfCell] = GR.ODValues[0];
                    }
                    else if (rbtnGrRate.Checked)
                    {
                        Data[IndexOfCell] = Math.Log(2) / GR.GrowthRate.GrowthRate;
                    }
                    else if (btnTimePoint.Checked && lstTimePoints.SelectedIndex>-1)
                    {
                        int TimePoint = lstTimePoints.SelectedIndex;
                        Data[IndexOfCell] = GR.ODValues[TimePoint];
                    }
                }
                //now to make the color map
                PT.makeSquares(Data);
                Graphics graphicsObj = e.Graphics;
                graphicsObj.DrawImage(PT.TheColoredSquaresBM, tabRobo.Left + 30, tabRobo.Top + 30, PT.TheColoredSquaresBM.Width, PT.TheColoredSquaresBM.Height);
                lblRobo.Text = "ROBOT DATA DISPLAYED";
            }
            catch
            {
                lblRobo.Text = "NO ROBOT DATA TO DISPLAY OR ERROR IN DISPLAYING IT";
            }
            this.ResumeLayout();
            
        }
        private void rbtnMaxOD_CheckedChanged(object sender, EventArgs e)
        {
            this.Refresh();
        }
        private void rbtnGrowthRate_CheckedChanged(object sender, EventArgs e)
        {
            this.Refresh();
        }
        private void rbtnRS_CheckedChanged(object sender, EventArgs e)
        {
            this.Refresh();
        }
        private void rbtnIOD_CheckedChanged(object sender, EventArgs e)
        {
            this.Refresh();
        }
        private void rbtnGrRate_CheckedChanged(object sender, EventArgs e)
        {
            this.Refresh();
        }

        
        private void btnDeleteFirstBlank_Click(object sender, EventArgs e)
        {
            try
            {
                SubtractFirstReadingFromAll();
                RefreshMultiplePlots();
            }
            catch (Exception thrown)
            {
                MessageBox.Show("Could not subtract blank, error is: " + thrown.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
        private void lstGrowthCurves_KeyDown(object sender, KeyEventArgs e)
        {

            if (e.KeyCode == Keys.Delete || e.KeyCode==Keys.Back) { btnDeleteCurve.PerformClick(); }
        }
        private void btnFitODRange_Click(object sender, EventArgs e)
        {
            try
            {
                double startOD = Convert.ToDouble(txtMinOD.Text);
                double endOD = Convert.ToDouble(txtMaxOD.Text);
                double endPercent=Convert.ToDouble(txtMaxODPercent.Text);
                foreach (object GRs in lstGrowthCurves.Items)
                {
                    try
                    {
                        GrowthData GR = (GrowthData)GRs;
                        if (!chkUsePercent.Checked)
                        {
                            GR.SetFittedODRange(startOD, endOD,chkODMustIncrease.Checked);
                        }
                        else
                        {
                            GR.SetFittedODRangeFromPercent(startOD, endPercent);
                        }
                    }
                    catch (Exception thrown)
                    {
                        MessageBox.Show("Failed to change range for : " + GRs.ToString() + "\nRecommend you shut down\n\n" + thrown.Message);
                    }
                }

                RefreshGraphs();
            }
            catch (Exception thrown) { MessageBox.Show("Error setting points\n\n" + thrown.Message); }
        }
        private void ChartPickData_MouseClick_1(object sender, MouseEventArgs e)
        {
            try
            {
                if (e.Button == MouseButtons.Left)
                {
                    CurveItem CI;
                    int outVal;
                    PointF location = (PointF)e.Location;
                    GrowthData GR = (GrowthData)lstGrowthCurves.SelectedItem;
                    //Somethimes this returns a value from the fitted line instead of
                    //from the data points, this work around will check for this, and remove it.
                    var q = ChartPickData.GraphPane.FindNearestPoint(location, out CI, out outVal);
                    bool IsCorrect = true;
                    if (CI.Points.Count == GR.TimeValuesDecimal.Length)
                    {
                        for( int pIndex=0;pIndex<CI.Points.Count;pIndex++)
                        {
                            if (CI.Points[pIndex].X != GR.TimeValuesDecimal[pIndex])
                            { IsCorrect = false; break; }
                            pIndex++;
                        }
                    }
                    else
                    { IsCorrect = false; }
                     PointPair selected = CI.Points[outVal];

                    //if not the right curve, find the point closest in the curve
                    //for the actual data
                    double XValue=selected.X;
                    if (!IsCorrect)
                    {
                        var Difs=from x in GR.TimeValuesDecimal select new {val=x,dif=Math.Abs(x-XValue)};
                        double smallestDif=(double)Difs.Min((a) => a.dif);
                        var values = from x in Difs where x.dif == smallestDif select x.val;
                        XValue = values.First();
                    }
                    RefitCurve(XValue);
                    ChartPickDataLastFitXValue=XValue;
                    
                }
            }
            catch { }
        }

        private void btnTimePoint_CheckedChanged(object sender, EventArgs e)
        {
            this.Refresh();

        }

        private void lstTimePoints_SelectedIndexChanged(object sender, EventArgs e)
        {
            this.Refresh();
        }

        private void chkShowFittedPick_CheckedChanged(object sender, EventArgs e)
        {
            RefreshGraphs();
        }

        private void openDirectoryWithExcelDataToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Cursor = Cursors.WaitCursor;
            try
            {
                ClearLists();
                folderBrowserDialog1.Description = "Select the directory that contains ONLY the data files";
                DialogResult DR = folderBrowserDialog1.ShowDialog();
                if (DR == DialogResult.OK)
                {
                    ImportRobotData.GetExcelData(folderBrowserDialog1.SelectedPath);
                    GetData(folderBrowserDialog1.SelectedPath + "\\" + ImportRobotData.NameofTempFile, false);
                    if (lstGrowthCurves.Items.Count == 48)
                    {
                        Is_48WellDataLoaded = true;
                        GrowthData GR = lstGrowthCurves.SelectedItem as GrowthData;
                        foreach (double value in GR.TimeValuesDecimal)
                        {
                            lstTimePoints.Items.Add(value.ToString("n3"));
                        }
                    }
                    else { Is_48WellDataLoaded = false; }
                    this.Text = "Growth Curve " + folderBrowserDialog1.SelectedPath;
                }
                this.Cursor = Cursors.Default;
            }
            catch (Exception thrown)
            {
                this.Cursor = Cursors.Default;
                MessageBox.Show("Could not load the data, the error was:\n\n" + thrown.Message);
            }
        }

        private void btnDelete2ndPoint_Click(object sender, EventArgs e)
        {
            try
            {
                SubtractSecondReadingFromAll();
                RefreshMultiplePlots();
            }
            catch (Exception thrown)
            {
                MessageBox.Show("Could not subtract blank, error is: " + thrown.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void btnDeleteAvg3asBlank_Click(object sender, EventArgs e)
        {
            try
            {
                SubtractAverageOfFirstThreeReadingsFromAll();
                RefreshMultiplePlots();
            }
            catch (Exception thrown)
            {
                MessageBox.Show("Could not subtract blank, error is: " + thrown.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void lstTreatmentSelection_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (lstTreatmentSelection.SelectedIndex > -1)
            {
                selectablePlateMap1.CurGroupToSelect = lstTreatmentSelection.SelectedIndex;
            }
        }

        private void chkTreatShowLog_CheckedChanged(object sender, EventArgs e)
        {
            RemakeTreatmentGraph();
        }

        private void btnClearTreatments_Click(object sender, EventArgs e)
        {
            selectablePlateMap1.ClearAllAssignments();
        }
        private void RefitCurve(double XValueToChange)
        {
            GrowthData GR = (GrowthData)lstGrowthCurves.SelectedItem;
            bool worked = GR.ChangePoint(XValueToChange);//, selected.Y);
            int IndexToReplace = lstGrowthCurves.SelectedIndex;
            if (worked)
            {
                lstGrowthCurves.Items[IndexToReplace] = GR;
                lstGrowthCurves.SelectedIndex = IndexToReplace;
            }
        }
        private void ChartN_MouseClick(object sender, MouseEventArgs e)
        {
            try
            {
               
                if (e.Button == MouseButtons.Left)
                {
                    CurveItem CI;
                    int outVal;
                    PointF location = (PointF)e.Location;
                    GrowthData GR = (GrowthData)lstGrowthCurves.SelectedItem;
                    //Somethimes this returns a value from the fitted line instead of
                    //from the data points, this work around will check for this, and remove it.
                    var q = ChartN.GraphPane.FindNearestPoint(location, out CI, out outVal);
                    bool IsCorrect = true;
                    if (CI.Points.Count == GR.TimeValuesDecimal.Length)
                    {
                        for (int pIndex = 0; pIndex < CI.Points.Count; pIndex++)
                        {
                            if (CI.Points[pIndex].X != GR.TimeValuesDecimal[pIndex])
                            { IsCorrect = false; break; }
                            pIndex++;
                        }
                    }
                    else
                    { IsCorrect = false; }
                    PointPair selected = CI.Points[outVal];

                    //if not the right curve, find the point closest in the curve
                    //for the actual data
                    double XValue = selected.X;
                    if (!IsCorrect)
                    {
                        var Difs = from x in GR.TimeValuesDecimal select new { val = x, dif = Math.Abs(x - XValue) };
                        double smallestDif = (double)Difs.Min((a) => a.dif);
                        var values = from x in Difs where x.dif == smallestDif select x.val;
                        XValue = values.First();
                    }
                    RefitCurve(XValue);
                    ChartNLastFitXValue = XValue;
  
                }
            }
            catch { }
        }

        private void importPlateKeyToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Cursor = Cursors.WaitCursor;
            try
            {
                 int Assigned=0;
                OpenFileDialog OFD = new OpenFileDialog();
                OFD.Title = "Select Plate Map File";
                OFD.Filter = "CSV FILE(*.csv) | *.csv";
                DialogResult DR = OFD.ShowDialog();
                if (DR == DialogResult.OK)
                {
                    selectablePlateMap1.ClearAllAssignments();
                    StreamReader SR = new StreamReader(OFD.OpenFile());
                    string line;
                    int curRow=0;
                   
                    while ((line = SR.ReadLine()) != null)
                    {
                        string[] sp = line.Split(',');
                        string rows="ABCDEFGH";
                        string cols="12345678";
                        int max= sp.Length== 8 ? 8 : sp.Length;
                        char well = rows[curRow];
                        for (int i = 0; i < max; i++)
                        {
                            try
                            {
                                int group = Convert.ToInt32(sp[i]);
                                char col = cols[i];
                                string name = well.ToString() + col.ToString();
                                selectablePlateMap1.AssignWellToGroup(name, group);
                                Assigned++;
                            }
                            catch (Exception thrown)
                            { }
                            
                        }
                        curRow++;
                        if (curRow > 6)
                            break;
                    }
                    SR.Close();
                    selectablePlateMap1.RecreateImage();
                }
                this.Cursor = Cursors.Default;
                MessageBox.Show(Assigned.ToString()+" Wells Assigned");
            }
            catch (Exception thrown)
            {
                this.Cursor = Cursors.Default;
                MessageBox.Show("Could not load the data, the error was:\n\n" + thrown.Message);
            }
        }


        private string ConnectionString;
        public void LoadUpDatabaseData(List<GrowthData> GDs,string ExpName,string DBConnString)
        {
            this.ConnectionString = DBConnString;
            this.Cursor = Cursors.WaitCursor;
            try
            {
                ClearLists();
                folderBrowserDialog1.Description = "Select the directory that contains ONLY the data files";
                foreach (GrowthData GD in GDs)
                {
                    AddGrowthRateDataToBoxes(GD);
                }
                if (lstGrowthCurves.Items.Count == 48)
                {
                    Is_48WellDataLoaded = true;
                    GrowthData GR = lstGrowthCurves.Items[0] as GrowthData;
                    foreach (double value in GR.TimeValuesDecimal)
                    {
                        lstTimePoints.Items.Add(value.ToString("n3"));
                    }
                }
                else { Is_48WellDataLoaded = false; }
                this.Text = "Growth Curve " + ExpName;
                this.Cursor = Cursors.Default;
                this.saveDataToDatabaseToolStripMenuItem.Enabled = true;
                this.importPreviousToolStripMenuItem.Enabled = false;
                this.openFileWithInitialToolStripMenuItem.Enabled = false;
                this.openDirectoryWithExcelDataToolStripMenuItem.Enabled = false;
                this.openDirectoryWithRobotDataToolStripMenuItem.Enabled = false;
                this.markAllGrowthRateValuesBadToolStripMenuItem.Enabled = true;
                this.markAllMaxODValuesBadToolStripMenuItem.Enabled = true;
                this.btnEnter.Enabled = false;
                this.MenuOpenFile.Enabled = false;
                btnFlagOD.Enabled = true;
                btnFlagGrowthRate.Enabled = true;
            }
            catch (Exception thrown)
            {
                this.Cursor = Cursors.Default;
                MessageBox.Show("Could not load the data, the error was:\n\n" + thrown.Message);
            }

        }

        private void markAllMaxODValuesBadToolStripMenuItem_Click(object sender, EventArgs e)
        {
            foreach (object GRs in lstGrowthCurves.Items)
            {
                GrowthData GR = (GrowthData)GRs;
                GR.db_MaxOD_Flag = true;
            }
        }

        private void markAllGrowthRateValuesBadToolStripMenuItem_Click(object sender, EventArgs e)
        {
            foreach (object GRs in lstGrowthCurves.Items)
            {
                GrowthData GR = (GrowthData)GRs;
                GR.db_GrowthRateFLAG = true;
            }
        }
        private void UpdateDataBase()
        {
            string lastCmd;
            try
            {
                //Update commands for the Results, the Experiment and the raw data
                List<string> DataTableUpdateCommands = new List<string>();
                OleDbConnection conn = new OleDbConnection(ConnectionString);
                Dictionary<int, short> ExpIDs = new Dictionary<int, short>(3);
                conn.Open();
                OleDbTransaction trann = conn.BeginTransaction();
                OleDbCommand cmd = new OleDbCommand("", conn, trann);
                //First the DataTable
                GrowthData GR=null;
                foreach (object GRs in lstGrowthCurves.Items)
                {
                    GR = (GrowthData)GRs;
                    ExpIDs[GR.db_ExperimentID] = (short)0;
                    
                    DataTableUpdateCommands.AddRange(GR.data_CreateDataTableUpdateString());
                }
                foreach (string cmdstr in DataTableUpdateCommands)
                {
                    cmd.CommandText = cmdstr;
                    lastCmd = cmdstr;
                    cmd.ExecuteNonQuery();
                }
                //Now the results table
                DataTableUpdateCommands.Clear();
                
                foreach (object GRs in lstGrowthCurves.Items)
                {
                    GR = (GrowthData)GRs;
                    DataTableUpdateCommands.AddRange(GR.data_CreateResultTableUpdateString());
                }
                foreach (string cmdstr in DataTableUpdateCommands)
                {
                    lastCmd = cmdstr;
                    cmd.CommandText = cmdstr;
                    cmd.ExecuteNonQuery();
                }
                //Now the Experiments Table
                foreach (int ExpID in ExpIDs.Keys)
                {
                    

                    string cmdstr = "UPDATE Experiments SET Experiments.Fitted = TRUE WHERE ExpID=" + ExpID.ToString();
                    if (GR.IsIsolateData)
                        cmdstr = "UPDATE IsoExperiments SET IsoExperiments.Fitted = TRUE WHERE ExpID=" + ExpID.ToString();
                    cmd.CommandText = cmdstr;
                    cmd.ExecuteNonQuery();
                }
                trann.Commit();
                conn.Close();
                MessageBox.Show("Database updated");
            }
            catch (Exception thrown)
            {
                MessageBox.Show("Error: " + thrown.Message);
            }
        }

        private void saveDataToDatabaseToolStripMenuItem_Click(object sender, EventArgs e)
        {
            UpdateDataBase();
        }

        private void btnFlagGrowthRate_Click(object sender, EventArgs e)
        {
            try
            {
                GrowthData GR = (GrowthData)lstGrowthCurves.SelectedItem;
                GR.db_GrowthRateFLAG = !GR.db_GrowthRateFLAG;
                lstallData(GR);
            }
            catch (Exception thrown)
            { MessageBox.Show("Error: " + thrown.Message); }
        }

        private void btnFlagOD_Click(object sender, EventArgs e)
        {
            try
            {
                GrowthData GR = (GrowthData)lstGrowthCurves.SelectedItem;
                GR.db_MaxOD_Flag=!GR.db_MaxOD_Flag;
                lstallData(GR);
            }
            catch(Exception thrown)
            {MessageBox.Show("Error: "+thrown.Message);}
        }

        private void btnMakeEvoGroups_Click(object sender, EventArgs e)
        {
            for (int i = 0; i < 48; i++)
            {
              selectablePlateMap1.AssignWellToGroup(selectablePlateMap1.IntsToCellName[i], 2);
            }
            selectablePlateMap1.AssignWellToGroup("A1", 1);
            selectablePlateMap1.AssignWellToGroup("F8", 1);
            selectablePlateMap1.AssignWellToGroup("F1", 3);
            selectablePlateMap1.AssignWellToGroup("A8", 3);
            selectablePlateMap1.RecreateImage();
            selectablePlateMap1.Refresh();
            
        }

        private void loadExcelFileWithODAndVenusDataToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Cursor = Cursors.WaitCursor;
            try
            {
                ClearLists();
                folderBrowserDialog1.Description = "Select the directory that contains ONLY the data files";
                DialogResult DR = folderBrowserDialog1.ShowDialog();
                if (DR == DialogResult.OK)
                {
                    ImportRobotData.GetExcelData(folderBrowserDialog1.SelectedPath);
                    GetData(folderBrowserDialog1.SelectedPath + "\\" + ImportRobotData.NameofTempFile, false);
                    if (lstGrowthCurves.Items.Count == 48)
                    {
                        Is_48WellDataLoaded = true;
                        GrowthData GR = lstGrowthCurves.SelectedItem as GrowthData;
                        foreach (double value in GR.TimeValuesDecimal)
                        {
                            lstTimePoints.Items.Add(value.ToString("n3"));
                        }
                    }
                    else { Is_48WellDataLoaded = false; }
                    this.Text = "Growth Curve " + folderBrowserDialog1.SelectedPath;
                }
                this.Cursor = Cursors.Default;
            }
            catch (Exception thrown)
            {
                this.Cursor = Cursors.Default;
                MessageBox.Show("Could not load the data, the error was:\n\n" + thrown.Message);
            }
        }

    }
}

